﻿from Tkinter import *
from dialog import NewDialog, SaveDialog, OpenDialog, ChangePaletteSizeDialog, ChangeMapSizeDialog, AboutDialog
from improvedButton import ImprovedButton
import tkMessageBox
import tkSimpleDialog
import os
from mapDatabase import *

IMAGES_DIR = 'images/'

class View:
    def __init__(self):
        self.tk = Tk()
        self.tk.title("Map Creator")
        self.tk.protocol('WM_DELETE_WINDOW', self.close_window)
        
        system = self.tk.tk.call('tk','windowingsystem')
        if system == 'aqua':
            self.tk.bind("<Command-n>",self.__new_event)
            self.tk.bind("<Command-s>",self.__save_event)
            self.tk.bind("<Command-o>",self.__open_event)
        else:
            self.tk.bind("<Control-n>",self.__new_event)
            self.tk.bind("<Control-s>",self.__save_event)
            self.tk.bind("<Control-o>",self.__open_event)
            
        
        # características do mapa
        self.map_size = (0, 0)
        self.sprite_size = (0, 0)
        self.palette_size = (5, 5)
        self.file_dir = ''
        self.file = ''
        
        # label que indica a imagem selecionada
        self.lbl_selected = None
        
        # identificador - da imagem selecionada - no dicionário images
        self.id_selected = None        
        
        self.images = dict()
        self.id_default_image = None
        
        self.buttons = list()
        
        self.__create_menu()
        self.top_panel = None
        self.map_panel = None
        self.palette_panel = None
        
    def __create_menu(self):
        menu_bar = Menu(self.tk)
        file_menu = Menu(menu_bar, tearoff=0)
        options_menu = Menu(menu_bar, tearoff=0)
        help_menu = Menu(menu_bar, tearoff=0)
        menu_bar.add_cascade(label="File", menu=file_menu)
        file_menu.add_command(label="New", command=self.new)
        file_menu.add_command(label="Open", command=self.open)
        file_menu.add_command(label="Save", command=self.save)
        file_menu.add_separator()
        file_menu.add_command(label="Exit", command=self.close_window)
        
        menu_bar.add_cascade(label="Options", menu=options_menu)
        options_menu.add_command(label="Map Size", command=self.change_map_size)
        options_menu.add_command(label="Palette Size", command=self.change_palette_size)
        options_menu.add_command(label="Separate Palette", command=self.separate_palette)
        
        menu_bar.add_cascade(label="Help", menu=help_menu)
        help_menu.add_command(label="About", command=self.about)        
        
        self.tk.config(menu=menu_bar)
        
    def __create_images(self):
        # remove possíveis imagens temporárias
        self.__delete_temp_images()
        
        # imagem
        file = self.file_dir + self.file
        image = PhotoImage(file=file, format='gif')
        image_w, image_h = image.width(), image.height()        
        
        # tamanho das subimagens que serão geradas
        sprite_w, sprite_h = self.sprite_size

        # total de imagens no arquivo
        cols, rows = (image_w // sprite_w) , (image_h // sprite_h)
        total_images = cols * rows
        
        if total_images == 0:
            return (None, None)
        
        # separa a string do arquivo em file_name e file_extension
        file_tmp = self.file.split('.')
        
        file_name, file_extention = tuple(file_tmp)
        
        # cria o dicionário images
        images = {}           
        for row in xrange(rows):
            for col in xrange(cols):
                index = row * cols + col
                try:
                    id = file_name + '_tmp_' + str(index)
                    image.write(self.file_dir + id + '.gif', format="gif", from_coords=(col*sprite_w, row*sprite_h, col*sprite_w+sprite_w, row*sprite_h+sprite_h))
                    images[id] = {'image':PhotoImage(file=self.file_dir + id + '.gif'),'image_position':(col*sprite_w, row*sprite_h)}
                except:
                    pass

        # define uma imagem default
        id_default_image = None
        if total_images >= 1 :
            id_default_image = file_name + '_tmp_' + str(0)

        return (images, id_default_image)
        
    def __create_top_panel(self):
        if self.id_default_image == None:
            return None
        panel = Frame(self.tk)
        label = Label(panel, text="Selecionado: ")
        label.pack(side=LEFT)
        
        self.lbl_selected = Label(panel)
        self.lbl_selected.pack(side=RIGHT)
        self.__set_selected(self.id_default_image)
        
        panel.pack(side=TOP)
        
        return panel       
        
    def __set_selected(self, id_selected):
        self.id_selected = id_selected
        img_selected = self.images[id_selected]['image']
        self.lbl_selected.config(image=img_selected)
   
    def __create_map_panel(self, database_elements=list()):
        if self.id_default_image == None:
            return None    
        # cria o painel mapa
        width, height = self.map_size
        panel = Frame(self.tk, width=width, height=height)
        # cria os botões
        self.__create_map_buttons(panel, database_elements)
        # exibe o painel
        panel.pack(side=TOP)
        
        return panel
        
    def __create_map_buttons(self, panel, database_elements=list()):  
        # cria uma lista vazia de botões
        self.buttons = list()        
            
        if len(database_elements) == 0:
            # tamanho do mapa
            width, height = self.map_size
            # tamanho das imagens
            sprite_width, sprite_height = self.sprite_size
            rows = height // sprite_height
            cols = width // sprite_width
            
            for col in xrange(cols):
                for row in xrange(rows):
                    id = self.id_default_image
                    image = self.images[id]['image']
                    image_position = self.images[id]['image_position']
                    position = (row,col)    
                    information = ''
                    # cria o botão
                    self.__create_map_button(panel, id, image_position, position, information, image)
                    
        else:
            for button in database_elements:
                # imagem
                id = button.get_id()
                image = self.images[id]['image']            
                # posição da subimagem em relação à imagem
                image_position = button.get_subimage()
                # posição na matriz
                row, col = position = button.get_position()
                # informacao
                information = button.get_information()
                # cria o botão
                self.__create_map_button(panel, id, image_position, position, information, image)
     
    def __create_map_button(self, panel, id, image_position, position, information, image):            
        button = ImprovedButton(panel, id, image_position, position, image=image)
        button.set_info(information)
        # dá efeito de achatado
        if information <> '':
            button.configure(relief=FLAT)
            
        button.bind("<Button-1>",self.button_map_click)
        if (self.tk.call('tk', 'windowingsystem')=='aqua'):
            button.bind("<Button-2>",self.button_map_right_click)
        else:
            button.bind("<Button-3>",self.button_map_right_click)
        row, col = position
        button.grid(row=row, column=col)                
        self.buttons.append(button)                

    def __create_palette_panel(self, type=Frame):
        if self.id_default_image == None:
            return None         
        panel = type(self.tk)
        panel.config(borderwidth=3, relief=RIDGE)
        rows, cols = self.palette_size       
        
        keys = self.images.keys()
        keys.sort()
        
        for col in xrange(cols):
            for row in xrange(rows):
                index = row * cols + col
                try:
                    id = keys[index]
                    image = self.images[id]['image']
                    image_position = self.images[id]['image_position']
                    position=(row,col)
                    # cria o botão
                    button = ImprovedButton(panel, id, image_position, position, image=image)
                    button.bind("<Button-1>",self.button_palette_click)
                    button.grid(row=row, column=col)
                except:
                    pass
        if isinstance(panel, Frame):
            panel.pack(side=BOTTOM)
        
        self.__set_selected(self.id_default_image)
        
        return panel

    def button_palette_click(self, event) :
        selected = event.widget.get_id()
        self.__set_selected(selected)
        
    def button_map_click(self, event) :
        # pega a referência do botão
        button = event.widget
        
        id = self.id_selected
        image = self.images[id]['image']
        image_position = self.images[id]['image_position']
        button.set_image(id, image_position, image)
    
    def button_map_right_click(self, event) :
        #pega a referência do botão
        button = event.widget
        
        old_info = button.get_info()
        new_info = tkSimpleDialog.askstring("Information","Information to link to this button", initialvalue=old_info)
        if new_info <> None:
            button.set_info(new_info)
            if new_info == "":
                button.configure(relief=RAISED)
            else:
                button.configure(relief=FLAT)
   
    def separate_path(self, path):
        path_separator = '\\'
        elements = path.split(path_separator)
        if len(elements) > 1:
            dir = path_separator.join(elements[:-1])
        else:
            path_separator = '/'
            elements = path.split(path_separator)
            dir = path_separator.join(elements[:-1])
            
        dir += path_separator
        file = elements[-1]
        return (dir, file)        
        
    def close_window(self):
        self.__delete_temp_images()
        self.tk.destroy()
        
    def __delete_temp_images(self):
        if self.images == None:
            return
        keys = self.images.keys()
        for file in keys :
            os.remove(self.file_dir + file + '.gif')
  
    def __destroy_panels(self):
        if self.top_panel <> None:
            self.top_panel.destroy()
        if self.map_panel <> None:
            self.map_panel.destroy()
        if self.palette_panel <> None:
            self.palette_panel.destroy()        
  
    def __new_event(self, event):
        self.new()
        
    def __open_event(self, event):
        self.open()
        
    def __save_event(self, event):
        self.save()        
  
    def new(self):
        dialog = NewDialog(self.tk, self.map_size, self.sprite_size, self.palette_size, self.file_dir+self.file)
        if dialog.is_ok() :
            self.map_size = dialog.get_map_size()
            self.sprite_size = dialog.get_sprite_size()
            #self.palette_size = dialog.get_palette_size()
            self.file_dir, self.file = self.separate_path(dialog.get_file())

            self.images, self.id_default_image = self.__create_images()        
            
            self.__destroy_panels()
            
            self.top_panel = self.__create_top_panel()        
            self.map_panel = self.__create_map_panel()        
            self.palette_panel = self.__create_palette_panel()
  
    def open(self):
        dialog = OpenDialog()
        database_file = dialog.get_file()
        if database_file == None:
            return
            
        path, file = self.separate_path(database_file)
            
        try:
            self.__destroy_panels()
        
            database = MapDatabase(database_file)

            header = database.get_header()
            # atributos do cabeçalho
            self.file_dir = path
            self.file = header.get_image_file()
            self.map_size = header.get_screen_size()
            self.sprite_size = header.get_sprite_size()
            
            # cria as imagens
            self.images, self.id_default_image = self.__create_images()
            
            # cria o painel mapa
            width, height = self.map_size
            panel = Frame(self.tk, width=width, height=height)
            
            # tamanho das imagens
            sprite_width, sprite_height = self.sprite_size
            rows = height // sprite_height
            cols = width // sprite_width            
            
            # ajustando os elementos
            elements = database.get_elements()
            
            self.top_panel = self.__create_top_panel()
            self.map_panel = self.__create_map_panel(elements)
            self.palette_panel = self.__create_palette_panel()
            
        except Exception as e:
            tkMessageBox.showerror('Error', 'Cannot open the file\n' + str(e))            
            print e
        else:
            tkMessageBox.showinfo('Success', 'File has been opened!\n')
            database.close() 
            
    
    def save(self):
        if self.map_size == (0,0):
            tkMessageBox.showwarning('Attention', 'You have to create a map first\n')
            return
    
        dialog = SaveDialog()
        database_file = dialog.get_file()
        if database_file == None:
            return
            
        try:
            header = MapHeader(image_file=self.file, screen_size=self.map_size, sprite_size=self.sprite_size)
            database = MapDatabase(database_file, header, remove=True)
            
            for button in self.buttons:
                # identificador
                id = button.get_id()
                # posição da subimagem em relação à imagem
                image = button.get_image()
                # posição na matriz
                position = button.get_position()
                # informacao
                information = button.get_info()
                
                element = MapElement(id=id, subimage=image, position=position, information=information)
                database.insert_element(element)

        except Exception as e:
            tkMessageBox.showerror('Error', 'Cannot save the file\n' + str(e))            
            print e
        else:
            tkMessageBox.showinfo('Success', 'File has been saved!\n')
            database.close()
        
    def separate_palette(self):
        if self.palette_panel <> None:
            self.palette_panel.destroy()
            self.palette_panel = self.__create_palette_panel(type=Toplevel)        
        
    def change_map_size(self):
        dialog = ChangeMapSizeDialog(self.tk, self.map_size)
        if dialog.is_ok() :
            if self.map_panel <> None:
                sprite_w, sprite_h = self.sprite_size
                w, h = self.map_size
                new_w, new_h = dialog.get_map_size()
                rows, cols = int(h // sprite_h), int(w // sprite_w)
                new_rows, new_cols = int(new_h // sprite_h), int(new_w // sprite_w)
                
                if new_rows < rows or new_cols < cols:
                    temp_buttons = self.buttons[:]
                    for button in temp_buttons:
                        i, j = button.get_position()
                        if i >= new_rows or j >= new_cols:
                            button.pack_forget()
                            button.destroy()
                            self.buttons.remove(button)
                    
                if new_rows > rows:
                    for i in xrange(rows, new_rows):
                        for j in xrange(cols):
                            id = self.id_default_image
                            image = self.images[id]['image']
                            image_position = self.images[id]['image_position']
                            position = (i,j)    
                            information = ''
                            self.__create_map_button(self.map_panel, id, image_position, position, information, image)
                            
                            
                if new_cols > cols:
                    for i in xrange(new_rows):
                        for j in xrange(cols, new_cols):
                            id = self.id_default_image
                            image = self.images[id]['image']
                            image_position = self.images[id]['image_position']
                            position = (i,j)    
                            information = ''
                            self.__create_map_button(self.map_panel, id, image_position, position, information, image)
                            
            self.map_size = dialog.get_map_size()

    def change_palette_size(self):
        dialog = ChangePaletteSizeDialog(self.tk, self.palette_size)
        if dialog.is_ok() :
            self.palette_size = dialog.get_palette_size()
            
            if self.palette_panel <> None:
                self.palette_panel.destroy()
                self.palette_panel = self.__create_palette_panel()
        
        
    def about(self):
        dialog = AboutDialog(self.tk)
   
    def run(self):
        self.tk.mainloop()
